﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using TaskManager.Domain.BusinessObjects;
using TaskManager.Domain.Repositories;
using TaskManager.Domain.Services;
using TaskManager.Web.Filters;

namespace TaskManager.Web.Controllers
{
    [Log]
    public class TestServerController : Controller
    {
        private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(TestServerController));
        
        private readonly Lazy<IProjectRepository> _projectRepository;
        private readonly Lazy<IUserActionLogger> _userActionLogger;
        private readonly Lazy<IUserRepository> _userRepository;
        private readonly Lazy<ITaskRepository> _taskRepository;
        private readonly IUnitOfWork _unitOfWork;

        public TestServerController(Lazy<IProjectRepository> projectRepository, Lazy<IUserRepository> userRepository, Lazy<ITaskRepository> taskRepository, 
            IUnitOfWork unitOfWork, Lazy<IUserActionLogger> userActionLogger)
        {
            _projectRepository = projectRepository;
            _taskRepository = taskRepository;
            _unitOfWork = unitOfWork;
            _userRepository = userRepository;
            _userActionLogger = userActionLogger;

            Log.Debug("Created TestServerController");
        }

        //
        // GET: /TestServer/CreateProject?name=project1&&description=description1

        public void CreateProject(string name, string description)
        {
            var project = new Project(name, description, _userActionLogger.Value);
            _projectRepository.Value.Insert(project);
            _unitOfWork.Save();

            Log.Debug("Project Id=[" + project.Id + "]");
        }

        //
        // GET: /TestServer/GetProjectId?name=project1

        public string GetProjectId(string name)
        {
            int projectId = _projectRepository.Value.FindByName(name).Id;

            return projectId.ToString();
        }

        //
        // GET: /TestServer/CloseProject?name=project1

        public void CloseProject(string name)
        {
            Project project = _projectRepository.Value.FindByName(name);

            project.Close();

            _unitOfWork.Save();
        }

        //
        // GET: /TestServer/CreateTask/summary=task1&&description=descr1&&project=project1&&priority=2&&assignee=user1&&owner=user2

        public void CreateTask(string summary, string description, string project, int priority, string assignee, string owner)
        {
            Project prj = _projectRepository.Value.FindByName(project);
            User userAssignee = _userRepository.Value.FindByName(assignee);
            User userOwner = _userRepository.Value.FindByName(owner);

            var task = new Task(prj, summary, description, userOwner, userAssignee, priority, _userActionLogger.Value);
            _taskRepository.Value.Insert(task);

            _unitOfWork.Save();

            Log.Debug("Task Id=[" + task.Id + "]");
        }

        //
        // GET: /TestServer/GetTaskId?summary=task1

        public string GetTaskId(string summary)
        {
            int taskId = _taskRepository.Value.All.Where(t => t.Summary == summary).Single().Id;

            return taskId.ToString();
        }

        //
        // GET: /TestServer/StartTask?summary=task1

        public void StartTask(string summary)
        {
            Task task = _taskRepository.Value.All.Where(t => t.Summary == summary).Single();

            task.Start();

            _unitOfWork.Save();
        }

        //
        // GET: /TestServer/CompleteTask?summary=task1

        public void CompleteTask(string summary)
        {
            Task task = _taskRepository.Value.All.Where(t => t.Summary == summary).Single();

            task.Complete();

            _unitOfWork.Save();
        }

        //
        // GET: /TestServer/CreateUser?name=user1&&password=123456

        public void CreateUser(string name, string password)
        {
            Tuple<User, string> res = _userRepository.Value.CreateUser(name, password, "email1",
                () => _unitOfWork.Save());

            if (res.Item1 == null)
                throw new Exception(res.Item2);

            Log.Debug("New user created.User name=[" + name + "],user Id=[" + res.Item1.Id + "]");
        }

        //
        // GET: /TestServer/DeleteData

        public void DeleteData()
        {
            Log.Debug("Deleting tasks");
            List<int> taskIdsList = _taskRepository.Value.All.Select(task => task.Id).ToList();

            taskIdsList.ForEach(id => _taskRepository.Value.Delete(id));
            Log.Debug("Total [" + taskIdsList.Count + "] task(s) deleted");

            Log.Debug("Deleting projects");
            
            List<int> projectIdsList = _projectRepository.Value.All.Select(project => project.Id).ToList();

            projectIdsList.ForEach(id => _projectRepository.Value.Delete(id));
            Log.Debug("Total [" + projectIdsList.Count + "] project(s) deleted");

            _unitOfWork.Save();
        }

        //
        // GET: /TestServer/DeleteUsers?user=user1&&password=123456

        /// <summary>
        /// Deletes all user except the specified user. If specified user does not exist it will be created
        /// </summary>
        /// <param name="user">User who must be present in the database</param>
        /// <param name="password">User password</param>
        public void DeleteUsers(string user, string password)
        {
            Log.Debug("Deleting users");
            
            List<string> allUsers = _userRepository.Value.All.Select(u => u.Name).ToList();

            bool userExistFlag = false;

            foreach (string u in allUsers)
            {
                if (u == user)
                {
                    userExistFlag = true;
                    continue;
                }

                _userRepository.Value.Delete(u, () => _unitOfWork.Save());

                Log.Debug("Deleted user=[" + u + "]");
            }

            if(!userExistFlag)
            {
                Tuple<User, string> res = _userRepository.Value.CreateUser(user, password, "email1", () => _unitOfWork.Save());

                if (res.Item1 == null)
                    throw new Exception(res.Item2);

                Log.Debug("Created user=[" + user + "]");
            }
        }
    }
}